#include <jni.h>
#include <string>
#include "native-lib.h"

int m_child;
int m_parent=1;
const  char  *user_ID;

const  char  *PATH="/data/data/com.hhlkeepalive/my.socket";


extern "C"
JNIEXPORT void JNICALL
Java_com_hhlkeepalive_Watcher_creatLinuxServiceScoket(JNIEnv *env, jobject instance,
                                                      jstring userID_) {
    const char *userID = env->GetStringUTFChars(userID_, 0);

    //开始开启服务端的Socket（也就是子进程）
     pid_t pid=fork();
     if(pid<0){
         //失败
     } else if(pid==0){
        //成功
        LOGE ( "子进程来开启 %d");
         //开启Linux 的Socket
          child_do_work();
     }



    env->ReleaseStringUTFChars(userID_, userID);
}


void  child_do_work(){

    //开启Linux的Socket
    if(child_creat_server_socket()){
        //服务端的socket 链接开始读消息
        child_listen_msg();
    }


}




int child_creat_server_socket(){

    //创建Sockeat
    //1.简历socket服务<协议，传输方式【文件、流】，默认为0>
      int listenfd =  socket(AF_LOCAL,SOCK_STREAM,0);//返回一个句柄
      unlink(PATH);
      //声明结构体
      struct sockaddr_un addr;
      //清空结构体的内存
      memset(&addr,0, sizeof(sockaddr_un));
      //设置协议
      addr.sun_family=AF_LOCAL;
      //复制路径
      strcpy(addr.sun_path,PATH);

     if( bind(listenfd, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr))<0){
         //绑定错误
        // LOGE("绑定作物");
         return 0;
     }

     //<句柄，最多支持多少个客户端链接>
     listen(listenfd,5);

     int connfd;//客户端句柄

     //等待客户端进程链接
     while (true){
         //LOGE("子进程等待链接");
         //accept是一个阻塞式函数 等待客户端链接
         if((connfd=accept(listenfd,NULL,NULL))<0){
            if(errno==EINTR){
                //代表读取错误继续等待
                continue;
            } else{
                //LOGE("读取错误");
                return  0;
            }
         }

        LOGE("apk 主进程连接上 %d", m_child);

          m_child=connfd;

     }

}


void  child_listen_msg(){
    // 只读一次 只有当客户端被kill时结束链接的时候服务端的rade函数不再阻塞
    while (true){
        fd_set rfds;
        //清空端口号
        FD_ZERO(&rfds);
        FD_SET(m_child,&rfds);

        //设置一些超出函数
        struct  timeval timeout={3,0};
        int r= select(m_child+1,&rfds,NULL,NULL,&timeout);

         if(r<0){
             //限定只接受mchild客户端发的消息
             if(FD_ISSET(m_child,&rfds)){
                 //参数解释：客户端句柄，消息的缓冲区，长度
                 char   pkg[256] ={0};
                 //qpp进程被干掉之后收到消息不再阻塞   （主进程）客户端写到内容  没有进行任何的写入操作
                 int result= read(m_child,pkg, sizeof(pkg));
                 //读到内容的唯一方式就是客户端断开
                   LOGE("重启父进程  %d",result);
                  //开始重启主进程(某个服务 通过adb) 开启java服务

                 //文件的结对路劲，参数(执行这个文件的am命令)  传进来的userID，开启服务的全路径
                 execlp("am","am","startservice","--user",user_ID,"com.hhlkeepalive.ndkAlive.PushService",(char *)NULL);

                 break;
             }


         }

    }

}



//运行在主进程（客户端进程）
extern "C"
JNIEXPORT void JNICALL
Java_com_hhlkeepalive_Watcher_connectToService(JNIEnv *env, jobject instance) {

    // TODO
    int sockfd;
    struct sockaddr_un addr;
    while(true){
        LOGE("客户端 父进程开始链接");
        sockfd=socket(AF_LOCAL,SOCK_STREAM,0);
        if(sockfd<0){
            return;
        }
        memset(&addr,0, sizeof(sockaddr_un));
        addr.sun_family=AF_LOCAL;
        strcpy(addr.sun_path,PATH);
        if(connect(sockfd,(const sockaddr*)&addr, sizeof(addr))<0){
            LOGE("链接失败 休眠");
            //链接失败
            close(sockfd);
            //链接失败休眠（在连接的时候客户端有可能不存在）
            sleep(1);
            continue;
        }
        //链接成功
        m_parent=sockfd;
        LOGE("链接成功 父进程跳出循环");
        break;

    }




}